#include "daemon.h"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <string>

namespace edm{
namespace common{
    
daemon_t::daemon_t(const char* root,
				 const char* user,
				 const char* group):
				 m_chroot_jail(root),
				 m_user(user),
				 m_group(group)
{
}
void daemon_t::daemonize()
{
	this->fork();
	this->setsid();
	this->fork();
	this->chroot();
	this->set_user_and_group();
	this->close_fds();		
}
void daemon_t::fork(void)
{
	pid_t pid;

	pid = ::fork();
	if (pid < 0)
	{
		perror ("daemon::fork");
		exit (EXIT_FAILURE);
	}
	else if (pid != 0)
	{
		exit (EXIT_SUCCESS);
	}		
}

void daemon_t::setsid (void)
{
	if (::setsid() == -1)
	{
		perror ("daemon::setsid");
		exit (EXIT_FAILURE);
	}	
}

void daemon_t::chroot (void)
{
	uid_t uid = getuid();

	if (uid)
	{
		if (chdir (m_chroot_jail.data()) < 0)
		{
			perror ("daemon::chroot");
			exit (EXIT_FAILURE);
		}
	}
	else
	{
		if ((::chroot (m_chroot_jail.data()) < 0) || 
			(chdir (m_chroot_jail.data()) < 0))
		{
			perror ("daemon::chroot");
			exit (EXIT_FAILURE);
		}
	}
}

void daemon_t::signal_ignore(int sig)
{
	if (::signal (sig, SIG_IGN) == SIG_ERR )
	{
		perror ("daemon::signal_ignore");
		exit (EXIT_FAILURE);
	}	
}

void daemon_t::close_fds (void)
{
	int fd = open ("/dev/null", O_RDWR, 0);

	if (fd == -1)
	{
		perror ("daemon::close_fds");
		exit (EXIT_FAILURE);
	}
	
	dup2 (fd, STDIN_FILENO);
	dup2 (fd, STDOUT_FILENO);
	dup2 (fd, STDERR_FILENO);
	
	if (fd > 2) close (fd);	
}

void daemon_t::set_user_and_group (void)
{
	struct passwd *user_info;
	struct group  *group_info;

	if (getuid() == 0)
	{
		if ((group_info = getgrnam (m_group.data())) == NULL)
		{
			perror ("daemon::set_user_and_group");
			exit (EXIT_FAILURE);
		}
	
		if (setgid (group_info->gr_gid) < 0)
		{
			perror ("daemon::set_user_and_group");
			exit (EXIT_FAILURE);
		}
	
		if ((user_info = getpwnam (m_user.data())) == NULL)
		{
			perror ("daemon::set_user_and_group");
			exit (EXIT_FAILURE);
		}
	
		if (setuid (user_info->pw_uid) < 0)
		{
			perror ("daemon::set_user_and_group");
			exit (EXIT_FAILURE);
		}
	}	
}    
    
}}


